package com.atguigu.guli.service.sms.service.impl;

import com.atguigu.guli.common.utils.FormUtils;
import com.atguigu.guli.common.utils.HttpUtils;
import com.atguigu.guli.common.utils.RandomUtils;
import com.atguigu.guli.service.base.exception.GuliException;
import com.atguigu.guli.service.base.result.ResultCodeEnum;
import com.atguigu.guli.service.sms.config.SmsProperties;
import com.atguigu.guli.service.sms.service.SmsService;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class SmsServiceImpl implements SmsService {

    @Autowired
    private RedisTemplate redisTemplate;  // 注入redis, 保存验证码

    @Autowired
    private SmsProperties smsProperties;  // 注入验证码需要的配置信息


    // 发送短信接口
    @Override
    public void sendMsg(String mobile) {

        // 1, 验证手机号码格式
        if (!FormUtils.isMobile(mobile)) {
            throw new GuliException(ResultCodeEnum.LOGIN_MOBILE_ERROR);
        }

        // 2, 限制验证码获取次数, 一分钟1次, 每天最多5次

        // 一分钟只能获取一次验证码, 判断key是否存在, 如果key存在则还未超过1分钟
        String mobileCodePerMinKey = "code:pre:min:" + mobile;  // redis保存一分钟计时的 key
        if (redisTemplate.hasKey(mobileCodePerMinKey)) {
            throw new GuliException(ResultCodeEnum.SMS_SEND_ERROR_BUSINESS_LIMIT_CONTROL);
        }
        // 每天获取验证码次数不能超过5次
        String mobileCodePerDayKey = "code:pre:day:" + mobile;  // redis保存验证码获取次数的key
        Object countObj = redisTemplate.opsForValue().get(mobileCodePerDayKey);
        if (countObj != null) {
            if (Integer.parseInt(countObj.toString()) >= 5) {
                throw new GuliException(ResultCodeEnum.SMS_SEND_ERROR_COUNT_LIMIT_CONTROL);
            }
        } else {
            // 如果此手机号码还没有获取验证码, 次数设置为0, 保存时间为24小时
            redisTemplate.opsForValue().set(mobileCodePerDayKey, 0, 24, TimeUnit.HOURS);
        }

        // 3, 生成验证码
        String sixBitRandom = RandomUtils.getSixBitRandom();

        // 4, 发送验证码
        //appcode: 8e45699f00ff4bdbb807664045acd813(老师)
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + smsProperties.getAppcode());
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("mobile", mobile);
        querys.put("param", "**code**:"+sixBitRandom+",**minute**:10");
        querys.put("smsSignId", smsProperties.getSmsSignId());
        querys.put("templateId", smsProperties.getTemplateId());
        Map<String, String> bodys = new HashMap<String, String>();

        try {
            // HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            HttpResponse response = HttpUtils.doPost(smsProperties.getHost(),
                    smsProperties.getPath(),
                    smsProperties.getMethod(),
                    headers, querys, bodys);
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");

            // 判断短信发送成功还是失败
            Gson gson = new Gson();
            Map map = gson.fromJson(result, Map.class);
            String resultCode = map.get("code").toString();
            if (!"0".equals(resultCode)) {
                throw new GuliException(ResultCodeEnum.SMS_SEND_ERROR);
            }

            //短信发送成功
            //5、后端缓存验证码
            //拼接当前手机号码唯一的key; sixBitRando: 验证码
            String mobileCodeKey = "code:code:" + mobile;
            redisTemplate.opsForValue().set( mobileCodeKey,sixBitRandom,10, TimeUnit.MINUTES);
            //6、更新用户获取验证码的频率
            // 1分钟内不能再次获取验证码

            redisTemplate.opsForValue().set(mobileCodePerMinKey ,mobileCodePerMinKey, 1 , TimeUnit.MINUTES);
            //更新手机号码今天获取验证码的次数
            // incr key;  如果key不存在，默认值为0，加完之后变为1  ，如果key存在且是数字，自增1
            redisTemplate.opsForValue().increment(mobileCodePerDayKey);

        } catch (Exception e) {
            // e.printStackTrace();
            log.error(ExceptionUtils.getStackTrace(e));
            throw new GuliException(ResultCodeEnum.SMS_SEND_ERROR);
        }
    }
}
